home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / WWW / Library / Implementation / HTAABrow.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  26.2 KB  |  928 lines

  1.  
  2. /* MODULE                            HTAABrow.c
  3. **        BROWSER SIDE ACCESS AUTHORIZATION MODULE
  4. **
  5. **    Containts the code for keeping track on server hostnames,
  6. **    port numbers, scheme names, usernames, passwords
  7. **    (and servers' public keys).
  8. **
  9. ** IMPORTANT:
  10. **    Routines in this module use dynamic allocation, but free
  11. **    automatically all the memory reserved by them.
  12. **
  13. **    Therefore the caller never has to (and never should)
  14. **    free() any object returned by these functions.
  15. **
  16. **    Therefore also all the strings returned by this package
  17. **    are only valid until the next call to the same function
  18. **    is made. This approach is selected, because of the nature
  19. **    of access authorization: no string returned by the package
  20. **    needs to be valid longer than until the next call.
  21. **
  22. **    This also makes it easy to plug the AA package in:
  23. **    you don't have to ponder whether to free() something
  24. **    here or is it done somewhere else (because it is always
  25. **    done somewhere else).
  26. **
  27. **    The strings that the package needs to store are copied
  28. **    so the original strings given as parameters to AA
  29. **    functions may be freed or modified with no side effects.
  30. **
  31. **    The AA package does not free() anything else than what
  32. **    it has itself allocated.
  33. **
  34. ** AUTHORS:
  35. **    AL    Ari Luotonen    luotonen@dxcern.cern.ch
  36. **
  37. ** HISTORY:
  38. **    Oct 17    AL    Made corrections suggested by marca:
  39. **            Added  if (!realm->username) return NULL;
  40. **            Changed some ""s to NULLs.
  41. **            Now doing calloc() to init uuencode source;
  42. **            otherwise HTUU_encode() reads uninitialized memory
  43. **            every now and then (not a real bug but not pretty).
  44. **            Corrected the formula for uuencode destination size.
  45. ** BUGS:
  46. **
  47. **
  48. */
  49.  
  50. #include "HTUtils.h"
  51. #include <string.h>        /* strchr() */
  52. #include "HTString.h"
  53. #include "HTParse.h"        /* URL parsing function        */
  54. #include "HTList.h"        /* HTList object        */
  55. #include "HTAlert.h"        /* HTConfirm(), HTPrompt()    */
  56. #include "HTAAUtil.h"        /* AA common to both sides    */
  57. #include "HTAssoc.h"        /* Assoc list            */
  58. #include "HTAABrow.h"        /* Implemented here        */
  59. #include "HTUU.h"        /* Uuencoding and uudecoding    */
  60.  
  61. #include "LYLeaks.h"
  62.  
  63. /*
  64. ** Local datatype definitions
  65. **
  66. ** HTAAServer contains all the information about one server.
  67. */
  68. typedef struct {
  69.  
  70.     char *    hostname;    /* Host's name            */
  71.     int        portnumber;    /* Port number            */
  72.     HTList *    setups;        /* List of protection setups    */
  73.                                 /* on this server; i.e. valid    */
  74.                                 /* authentication schemes and    */
  75.                                 /* templates when to use them.    */
  76.                                 /* This is actually a list of    */
  77.                                 /* HTAASetup objects.        */
  78.     HTList *    realms;        /* Information about passwords    */
  79. } HTAAServer;
  80.  
  81.  
  82. /*
  83. ** HTAASetup contains information about one server's one
  84. ** protected tree of documents.
  85. */
  86. typedef struct {
  87.     HTAAServer *server;        /* Which server serves this tree         */
  88.     char *    template;    /* Template for this tree             */
  89.     HTList *    valid_schemes;    /* Valid authentic.schemes                */
  90.     HTAssocList**scheme_specifics;/* Scheme specific params             */
  91.     BOOL    retry;        /* Failed last time -- reprompt (or whatever)*/
  92. } HTAASetup;
  93.  
  94.  
  95. /*
  96. ** Information about usernames and passwords in
  97. ** Basic and Pubkey authentication schemes;
  98. */
  99. typedef struct {
  100.     char *    realmname;    /* Password domain name        */
  101.     char *    username;    /* Username in that domain    */
  102.     char *    password;    /* Corresponding password    */
  103. } HTAARealm;
  104.  
  105.  
  106.  
  107. /*
  108. ** Module-wide global variables
  109. */
  110.  
  111. PRIVATE HTList *server_table    = NULL;    /* Browser's info about servers         */
  112. PRIVATE char *secret_key    = NULL;    /* Browser's latest secret key       */
  113. PRIVATE HTAASetup *current_setup= NULL;    /* The server setup we are currently */
  114.                                         /* talking to                 */
  115. PRIVATE char *current_hostname    = NULL;    /* The server's name and portnumber  */
  116. PRIVATE int current_portnumber    = 80;    /* where we are currently trying to  */
  117.                                         /* connect.                 */
  118. PRIVATE char *current_docname    = NULL;    /* The document's name we are        */
  119.                                         /* trying to access.             */
  120. PRIVATE char *HTAAForwardAuth    = NULL;    /* Authorization: line to forward    */
  121.                                         /* (used by gateway httpds)         */
  122.  
  123.  
  124. /*** HTAAForwardAuth for enabling gateway-httpds to forward Authorization ***/
  125.  
  126. PUBLIC void HTAAForwardAuth_set ARGS2(CONST char *, scheme_name,
  127.                       CONST char *, scheme_specifics)
  128. {
  129.     int len = 20 + (scheme_name      ? strlen(scheme_name)      : 0) 
  130.              + (scheme_specifics ? strlen(scheme_specifics) : 0);
  131.  
  132.     FREE(HTAAForwardAuth);
  133.     if (!(HTAAForwardAuth = (char*)malloc(len)))
  134.     outofmem(__FILE__, "HTAAForwardAuth_set");
  135.  
  136.     strcpy(HTAAForwardAuth, "Authorization: ");
  137.     if (scheme_name) {
  138.     strcat(HTAAForwardAuth, scheme_name);
  139.     strcat(HTAAForwardAuth, " ");
  140.     if (scheme_specifics) {
  141.         strcat(HTAAForwardAuth, scheme_specifics);
  142.     }
  143.     }
  144. }
  145.  
  146.  
  147. PUBLIC void HTAAForwardAuth_reset NOARGS
  148. {
  149.     FREE(HTAAForwardAuth);
  150. }
  151.  
  152.  
  153. /**************************** HTAAServer ***********************************/
  154.  
  155.  
  156. /* PRIVATE                        HTAAServer_new()
  157. **        ALLOCATE A NEW NODE TO HOLD SERVER INFO
  158. **        AND ADD IT TO THE LIST OF SERVERS
  159. ** ON ENTRY:
  160. **    hostname    is the name of the host that the server
  161. **            is running in.
  162. **    portnumber    is the portnumber which the server listens.
  163. **
  164. ** ON EXIT:
  165. **    returns        the newly-allocated node with all the strings
  166. **            duplicated.
  167. **            Strings will be automatically freed by
  168. **            the function HTAAServer_delete(), which also
  169. **            frees the node itself.
  170. */
  171. PRIVATE HTAAServer *HTAAServer_new ARGS2(CONST char*,    hostname,
  172.                      int,        portnumber)
  173. {
  174.     HTAAServer *server;
  175.  
  176.     if (!(server = (HTAAServer *)malloc(sizeof(HTAAServer))))
  177.     outofmem(__FILE__, "HTAAServer_new");
  178.  
  179.     server->hostname    = NULL;
  180.     server->portnumber    = (portnumber > 0 ? portnumber : 80);
  181.     server->setups    = HTList_new();
  182.     server->realms    = HTList_new();
  183.  
  184.     if (hostname) StrAllocCopy(server->hostname, hostname);
  185.  
  186.     if (!server_table) server_table = HTList_new();
  187.     
  188.     HTList_addObject(server_table, (void*)server);
  189.  
  190.     return server;
  191. }
  192.  
  193.  
  194. /* PRIVATE                        HTAAServer_delete()
  195. **
  196. **    DELETE THE ENTRY FOR THE SERVER FROM THE HOST TABLE,
  197. **    AND FREE THE MEMORY USED BY IT.
  198. **
  199. ** ON ENTRY:
  200. **    killme        points to the HTAAServer to be freed.
  201. **
  202. ** ON EXIT:
  203. **    returns        nothing.
  204. */
  205. #ifdef NOT_NEEDED_IT_SEEMS
  206. PRIVATE void HTAASetup_delete();    /* Forward */
  207. PRIVATE void HTAAServer_delete ARGS1(HTAAServer *, killme)
  208. {
  209.     if (killme) {
  210.     HTList *cur1 = killme->setups;
  211.     HTList *cur2 = killme->realms;
  212.     HTAASetup *setup;
  213.     HTAARealm *realm;
  214.  
  215.     while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur1)))
  216.         HTAASetup_delete(setup);
  217.     HTList_delete(killme->setups);
  218.  
  219.     while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur2)))
  220.         ;    /* This sould free() the realm */
  221.     HTList_delete(killme->realms);
  222.  
  223.     FREE(killme->hostname);
  224.  
  225.     HTList_removeObject(server_table, (void*)killme);
  226.  
  227.     free(killme);
  228.     }
  229. }
  230. #endif /*NOT_NEEDED_IT_SEEMS*/
  231.  
  232.  
  233. /* PRIVATE                        HTAAServer_lookup()
  234. **        LOOK UP SERVER BY HOSTNAME AND PORTNUMBER
  235. ** ON ENTRY:
  236. **    hostname    obvious.
  237. **    portnumber    if non-positive defaults to 80.
  238. **
  239. **    Looks up the server in the module-global server_table.
  240. **
  241. ** ON EXIT:
  242. **    returns        pointer to a HTAAServer structure
  243. **            representing the looked-up server.
  244. **            NULL, if not found.
  245. */
  246. PRIVATE HTAAServer *HTAAServer_lookup ARGS2(CONST char *, hostname,
  247.                         int,      portnumber)
  248. {
  249.     if (hostname) {
  250.     HTList *cur = server_table;
  251.     HTAAServer *server;
  252.  
  253.     if (portnumber <= 0) portnumber = 80;
  254.  
  255.     while (NULL != (server = (HTAAServer*)HTList_nextObject(cur))) {
  256.         if (server->portnumber == portnumber  &&
  257.         0==strcmp(server->hostname, hostname))
  258.         return server;
  259.     }
  260.     }
  261.     return NULL;    /* NULL parameter, or not found */
  262. }
  263.  
  264.  
  265.  
  266.  
  267. /*************************** HTAASetup *******************************/    
  268.  
  269.  
  270. /* PRIVATE                        HTAASetup_lookup()
  271. **    FIGURE OUT WHICH AUTHENTICATION SETUP THE SERVER
  272. **    IS USING FOR A GIVEN FILE ON A GIVEN HOST AND PORT
  273. **
  274. ** ON ENTRY:
  275. **    hostname    is the name of the server host machine.
  276. **    portnumber    is the port that the server is running in.
  277. **    docname        is the (URL-)pathname of the document we
  278. **            are trying to access.
  279. **
  280. **     This function goes through the information known about
  281. **    all the setups of the server, and finds out if the given
  282. **    filename resides in one of the protected directories.
  283. **
  284. ** ON EXIT:
  285. **    returns        NULL if no match.
  286. **            Otherwise, a HTAASetup structure representing
  287. **            the protected server setup on the corresponding
  288. **            document tree.
  289. **            
  290. */
  291. PRIVATE HTAASetup *HTAASetup_lookup ARGS3(CONST char *, hostname,
  292.                       int,        portnumber,
  293.                       CONST char *, docname)
  294. {
  295.     HTAAServer *server;
  296.     HTAASetup *setup;
  297.  
  298.     if (portnumber <= 0) portnumber = 80;
  299.  
  300.     if (hostname && docname && *hostname && *docname &&
  301.     NULL != (server = HTAAServer_lookup(hostname, portnumber))) {
  302.  
  303.     HTList *cur = server->setups;
  304.  
  305.     if (TRACE) fprintf(stderr, "%s (%s:%d:%s)\n",
  306.                "HTAASetup_lookup: resolving setup for",
  307.                hostname, portnumber, docname);
  308.  
  309.     while (NULL != (setup = (HTAASetup*)HTList_nextObject(cur))) {
  310.         if (HTAA_templateMatch(setup->template, docname)) {
  311.         if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
  312.                    "HTAASetup_lookup:", docname,
  313.                    "matched template", setup->template);
  314.         return setup;
  315.         }
  316.         else if (TRACE) fprintf(stderr, "%s `%s' %s `%s'\n",
  317.                     "HTAASetup_lookup:", docname,
  318.                     "did NOT match template", setup->template);
  319.     } /* while setups remain */
  320.     } /* if valid parameters and server found */
  321.  
  322.     if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  323.                "HTAASetup_lookup: No template matched",
  324.                (docname ? docname : "(null)"),
  325.                "(so probably not protected)");
  326.  
  327.     return NULL;    /* NULL in parameters, or not found */
  328. }
  329.  
  330.  
  331.  
  332.  
  333. /* PRIVATE                        HTAASetup_new()
  334. **            CREATE A NEW SETUP NODE
  335. ** ON ENTRY:
  336. **    server        is a pointer to a HTAAServer structure
  337. **            to which this setup belongs.
  338. **    template    documents matching this template
  339. **            are protected according to this setup.
  340. **    valid_schemes    a list containing all valid authentication
  341. **            schemes for this setup.
  342. **            If NULL, all schemes are disallowed.
  343. **    scheme_specifics is an array of assoc lists, which
  344. **            contain scheme specific parameters given
  345. **            by server in Authenticate: fields.
  346. **            If NULL, all scheme specifics are
  347. **            set to NULL.
  348. ** ON EXIT:
  349. **    returns        a new HTAASetup node, and also adds it as
  350. **            part of the HTAAServer given as parameter.
  351. */
  352. PRIVATE HTAASetup *HTAASetup_new ARGS4(HTAAServer *,    server,
  353.                        char *,        template,
  354.                        HTList *,    valid_schemes,
  355.                        HTAssocList **,    scheme_specifics)
  356. {
  357.     HTAASetup *setup;
  358.  
  359.     if (!server || !template || !*template) return NULL;
  360.  
  361.     if (!(setup = (HTAASetup*)malloc(sizeof(HTAASetup))))
  362.     outofmem(__FILE__, "HTAASetup_new");
  363.  
  364.     setup->retry = NO;
  365.     setup->server = server;
  366.     setup->template = NULL;
  367.     if (template) StrAllocCopy(setup->template, template);
  368.     setup->valid_schemes = valid_schemes;
  369.     setup->scheme_specifics = scheme_specifics;
  370.  
  371.     HTList_addObject(server->setups, (void*)setup);
  372.  
  373.     return setup;
  374. }
  375.  
  376.  
  377.  
  378. /* PRIVATE                        HTAASetup_delete()
  379. **            FREE A HTAASetup STRUCTURE
  380. ** ON ENTRY:
  381. **    killme        is a pointer to the structure to free().
  382. **
  383. ** ON EXIT:
  384. **    returns        nothing.
  385. */
  386. #ifdef NOT_NEEDED_IT_SEEMS
  387. PRIVATE void HTAASetup_delete ARGS1(HTAASetup *, killme)
  388. {
  389.     int scheme;
  390.  
  391.     if (killme) {
  392.     if (killme->template) free(killme->template);
  393.     if (killme->valid_schemes)
  394.         HTList_delete(killme->valid_schemes);
  395.     for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++)
  396.         if (killme->scheme_specifics[scheme])
  397.         HTAssocList_delete(killme->scheme_specifics[scheme]);
  398.     free(killme);
  399.     }
  400. }
  401. #endif /*NOT_NEEDED_IT_SEEMS*/
  402.  
  403.  
  404.  
  405. /* PRIVATE                    HTAASetup_updateSpecifics()
  406. *        COPY SCHEME SPECIFIC PARAMETERS
  407. **        TO HTAASetup STRUCTURE
  408. ** ON ENTRY:
  409. **    setup        destination setup structure.
  410. **    specifics    string array containing scheme
  411. **            specific parameters for each scheme.
  412. **            If NULL, all the scheme specific
  413. **            parameters are set to NULL.
  414. **
  415. ** ON EXIT:
  416. **    returns        nothing.
  417. */
  418. PRIVATE void HTAASetup_updateSpecifics ARGS2(HTAASetup *,    setup,
  419.                          HTAssocList **,    specifics)
  420. {
  421.     int scheme;
  422.  
  423.     if (setup) {
  424.     if (setup->scheme_specifics) {
  425.         for (scheme=0; scheme < HTAA_MAX_SCHEMES; scheme++) {
  426.         if (setup->scheme_specifics[scheme])
  427.             HTAssocList_delete(setup->scheme_specifics[scheme]);
  428.         }
  429.         free(setup->scheme_specifics);
  430.     }
  431.     setup->scheme_specifics = specifics;
  432.     }
  433. }
  434.  
  435.  
  436.  
  437.  
  438. /*************************** HTAARealm **********************************/
  439.  
  440. /* PRIVATE                         HTAARealm_lookup()
  441. **        LOOKUP HTAARealm STRUCTURE BY REALM NAME
  442. ** ON ENTRY:
  443. **    realm_table    a list of realm objects.
  444. **    realmname    is the name of realm to look for.
  445. **
  446. ** ON EXIT:
  447. **    returns        the realm.  NULL, if not found.
  448. */
  449. PRIVATE HTAARealm *HTAARealm_lookup ARGS2(HTList *,    realm_table,
  450.                       CONST char *, realmname)
  451. {
  452.     if (realm_table && realmname) {
  453.     HTList *cur = realm_table;
  454.     HTAARealm *realm;
  455.     
  456.     while (NULL != (realm = (HTAARealm*)HTList_nextObject(cur))) {
  457.         if (0==strcmp(realm->realmname, realmname))
  458.         return realm;
  459.     }
  460.     }
  461.     return NULL;    /* No table, NULL param, or not found */
  462. }
  463.  
  464.  
  465.  
  466. /* PRIVATE                        HTAARealm_new()
  467. **        CREATE A NODE CONTAINING USERNAME AND
  468. **        PASSWORD USED FOR THE GIVEN REALM.
  469. **        IF REALM ALREADY EXISTS, CHANGE
  470. **        USERNAME/PASSWORD.
  471. ** ON ENTRY:
  472. **    realm_table    a list of realms to where to add
  473. **            the new one, too.
  474. **    realmname    is the name of the password domain.
  475. **    username    and
  476. **    password    are what you can expect them to be.
  477. **
  478. ** ON EXIT:
  479. **    returns        the created realm.
  480. */
  481. PRIVATE HTAARealm *HTAARealm_new ARGS4(HTList *,    realm_table,
  482.                        CONST char *,    realmname,
  483.                        CONST char *,    username,
  484.                        CONST char *,    password)
  485. {
  486.     HTAARealm *realm;
  487.  
  488.     realm = HTAARealm_lookup(realm_table, realmname);
  489.  
  490.     if (!realm) {
  491.     if (!(realm = (HTAARealm*)malloc(sizeof(HTAARealm))))
  492.         outofmem(__FILE__, "HTAARealm_new");
  493.     realm->realmname = NULL;
  494.     realm->username = NULL;
  495.     realm->password = NULL;
  496.     StrAllocCopy(realm->realmname, realmname);
  497.     if (realm_table) HTList_addObject(realm_table, (void*)realm);
  498.     }
  499.     if (username) StrAllocCopy(realm->username, username);
  500.     if (password) StrAllocCopy(realm->password, password);
  501.  
  502.     return realm;
  503. }
  504.  
  505.  
  506.  
  507.  
  508. /***************** Basic and Pubkey Authentication ************************/
  509.  
  510. /* PRIVATE                        compose_auth_string()
  511. **
  512. **        COMPOSE Basic OR Pubkey AUTHENTICATION STRING;
  513. **        PROMPTS FOR USERNAME AND PASSWORD IF NEEDED
  514. **
  515. ** ON ENTRY:
  516. **    scheme        is either HTAA_BASIC or HTAA_PUBKEY.
  517. **    realmname    is the password domain name.
  518. **
  519. ** ON EXIT:
  520. **    returns        a newly composed authorization string,
  521. **            (with, of course, a newly generated secret
  522. **            key and fresh timestamp, if Pubkey-scheme
  523. **            is being used).
  524. **            NULL, if something fails.
  525. ** NOTE:
  526. **    Like throughout the entire AA package, no string or structure
  527. **    returned by AA package needs to (or should) be freed.
  528. **
  529. */
  530. PRIVATE char *compose_auth_string ARGS2(HTAAScheme,    scheme,
  531.                     HTAASetup *,    setup)
  532. {
  533.     static char *result = NULL;    /* Uuencoded presentation, the result */
  534.     char *cleartext = NULL;    /* Cleartext presentation */
  535.     char *ciphertext = NULL;    /* Encrypted presentation */
  536.     int len;
  537.     char *username;
  538.     char *password;
  539.     char *realmname;
  540.     HTAARealm *realm;
  541.     char *inet_addr = "0.0.0.0";    /* Change... @@@@ */
  542.     char *timestamp = "42";        /* ... these @@@@ */
  543.     
  544.  
  545.     FREE(result);    /* From previous call */
  546.  
  547.     if ((scheme != HTAA_BASIC && scheme != HTAA_PUBKEY) || !setup ||
  548.     !setup->scheme_specifics || !setup->scheme_specifics[scheme] ||
  549.     !setup->server  ||  !setup->server->realms)
  550.     return NULL;
  551.  
  552.     realmname = HTAssocList_lookup(setup->scheme_specifics[scheme], "realm");
  553.     if (!realmname) return NULL;
  554.  
  555.     realm = HTAARealm_lookup(setup->server->realms, realmname);
  556.     if (!realm || setup->retry) {
  557.     char msg[100];
  558.  
  559.     if (!realm) {
  560.         if (TRACE) fprintf(stderr, "%s `%s' %s\n",
  561.                    "compose_auth_string: realm:", realmname,
  562.                    "not found -- creating");
  563.         realm = HTAARealm_new(setup->server->realms, realmname, NULL,NULL);
  564.         sprintf(msg,
  565.             "Enter username for %s at %s:",
  566.             realm->realmname,
  567.             setup->server->hostname ? setup->server->hostname : "??");
  568.     }
  569.     else {
  570.         sprintf(msg,"Enter username for %s at %s:", realm->realmname,
  571.             setup->server->hostname ? setup->server->hostname : "??");
  572.     }
  573.  
  574.     username = realm->username;
  575.     password = NULL;
  576.     HTPromptUsernameAndPassword(msg, &username, &password);
  577.  
  578.     FREE(realm->username);
  579.     FREE(realm->password);
  580.     realm->username = username;
  581.     realm->password = password;
  582.  
  583.     if (!realm->username)
  584.         return NULL;        /* Suggested by marca; thanks! */
  585.     }
  586.     
  587.     len = strlen(realm->username ? realm->username : "") +
  588.       strlen(realm->password ? realm->password : "") + 3;
  589.  
  590.     if (scheme == HTAA_PUBKEY) {
  591. #ifdef PUBKEY
  592.     /* Generate new secret key */
  593.     StrAllocCopy(secret_key, HTAA_generateRandomKey());
  594. #endif
  595.     /* Room for secret key, timestamp and inet address */
  596.     len += strlen(secret_key ? secret_key : "") + 30;
  597.     }
  598.     else
  599.     FREE(secret_key);
  600.  
  601.     if (!(cleartext  = (char*)calloc(len, 1)))
  602.     outofmem(__FILE__, "compose_auth_string");
  603.  
  604.     if (realm->username) strcpy(cleartext, realm->username);
  605.     else *cleartext = (char)0;
  606.  
  607.     strcat(cleartext, ":");
  608.  
  609.     if (realm->password) strcat(cleartext, realm->password);
  610.  
  611.     if (scheme == HTAA_PUBKEY) {
  612.     strcat(cleartext, ":");
  613.     strcat(cleartext, inet_addr);
  614.     strcat(cleartext, ":");
  615.     strcat(cleartext, timestamp);
  616.     strcat(cleartext, ":");
  617.     if (secret_key) strcat(cleartext, secret_key);
  618.  
  619.     if (!((ciphertext = (char*)malloc(2*len)) &&
  620.           (result     = (char*)malloc(3*len))))
  621.         outofmem(__FILE__, "compose_auth_string");
  622. #ifdef PUBKEY
  623.     HTPK_encrypt(cleartext, ciphertext, server->public_key);
  624.     HTUU_encode((unsigned char *)ciphertext, strlen(ciphertext), result);
  625. #endif
  626.     free(cleartext);
  627.     free(ciphertext);
  628.     }
  629.     else { /* scheme == HTAA_BASIC */
  630.     if (!(result = (char*)malloc(4 * ((len+2)/3) + 1)))
  631.         outofmem(__FILE__, "compose_auth_string");
  632.     HTUU_encode((unsigned char *)cleartext, strlen(cleartext), result);
  633.     free(cleartext);
  634.     }
  635.     return result;
  636. }
  637.  
  638.  
  639.  
  640. /* BROWSER PRIVATE                    HTAA_selectScheme()
  641. **        SELECT THE AUTHENTICATION SCHEME TO USE
  642. ** ON ENTRY:
  643. **    setup    is the server setup structure which can
  644. **        be used to make the decision about the
  645. **        used scheme.
  646. **
  647. **    When new authentication methods are added to library
  648. **    this function makes the decision about which one to
  649. **    use at a given time.  This can be done by inspecting
  650. **    environment variables etc.
  651. **
  652. **    Currently only searches for the first valid scheme,
  653. **    and if nothing found suggests Basic scheme;
  654. **
  655. ** ON EXIT:
  656. **    returns    the authentication scheme to use.
  657. */
  658. PRIVATE HTAAScheme HTAA_selectScheme ARGS1(HTAASetup *, setup)
  659. {
  660.     HTAAScheme scheme;
  661.  
  662.     if (setup && setup->valid_schemes) {
  663.     for (scheme=HTAA_BASIC; scheme < HTAA_MAX_SCHEMES; scheme++)
  664.         if (-1 < HTList_indexOf(setup->valid_schemes, (void*)scheme))
  665.         return scheme;
  666.     }
  667.     return HTAA_BASIC;
  668. }
  669.  
  670.  
  671.  
  672.  
  673. /* BROWSER PUBLIC                    HTAA_composeAuth()
  674. **
  675. **    SELECT THE AUTHENTICATION SCHEME AND
  676. **    COMPOSE THE ENTIRE AUTHORIZATION HEADER LINE
  677. **    IF WE ALREADY KNOW THAT THE HOST REQUIRES AUTHENTICATION
  678. **
  679. ** ON ENTRY:
  680. **    hostname    is the hostname of the server.
  681. **    portnumber    is the portnumber in which the server runs.
  682. **    docname        is the pathname of the document (as in URL)
  683. **
  684. ** ON EXIT:
  685. **    returns    NULL, if no authorization seems to be needed, or
  686. **        if it is the entire Authorization: line, e.g.
  687. **
  688. **           "Authorization: Basic username:password"
  689. **
  690. **        As usual, this string is automatically freed.
  691. */
  692. PUBLIC char *HTAA_composeAuth ARGS3(CONST char *,    hostname,
  693.                     CONST int,        portnumber,
  694.                     CONST char *,    docname)
  695. {
  696.     static char *result = NULL;
  697.     char *auth_string;
  698.     BOOL retry;
  699.     HTAAScheme scheme;
  700.  
  701.     /*
  702.     ** Make gateway httpds pass authorization field as it was received.
  703.     ** (This still doesn't really work because Authenticate: headers
  704.     **  from remote server are not forwarded to client yet so it cannot
  705.     **  really know that it should send authorization;  I will not
  706.     **  implement it yet because I feel we will soon change radically
  707.     **  the way requests are represented to allow multithreading
  708.     **  on server-side.  Life is hard.)
  709.     */
  710.     if (HTAAForwardAuth) {
  711.     if (TRACE) fprintf(stderr, "HTAA_composeAuth: %s\n",
  712.                "Forwarding received authorization");
  713.     StrAllocCopy(result, HTAAForwardAuth);
  714.     HTAAForwardAuth_reset();    /* Just a precaution */
  715.     return result;
  716.     }
  717.  
  718.     FREE(result);            /* From previous call */
  719.  
  720.     if (TRACE)
  721.     fprintf(stderr, 
  722.         "Composing Authorization for %s:%d/%s\n",
  723.         hostname, portnumber, docname);
  724.  
  725.     if (current_portnumber != portnumber ||
  726.     !current_hostname || !current_docname ||
  727.     !hostname         || !docname         ||
  728.     0 != strcmp(current_hostname, hostname) ||
  729.     0 != strcmp(current_docname, docname)) {
  730.  
  731.     retry = NO;
  732.  
  733.     current_portnumber = portnumber;
  734.     
  735.     if (hostname) StrAllocCopy(current_hostname, hostname);
  736.     else FREE(current_hostname);
  737.  
  738.     if (docname) StrAllocCopy(current_docname, docname);
  739.     else FREE(current_docname);
  740.     }
  741.     else retry = YES;
  742.     
  743.     if (!current_setup || !retry)
  744.     current_setup = HTAASetup_lookup(hostname, portnumber, docname);
  745.  
  746.     if (!current_setup)
  747.     return NULL;
  748.  
  749.  
  750.     switch (scheme = HTAA_selectScheme(current_setup)) {
  751.       case HTAA_BASIC:
  752.       case HTAA_PUBKEY:
  753.     auth_string = compose_auth_string(scheme, current_setup);
  754.     break;
  755.       case HTAA_KERBEROS_V4:
  756.     /* OTHER AUTHENTICATION ROUTINES ARE CALLED HERE */
  757.       default:
  758.     {
  759.         char msg[100];
  760.         sprintf(msg, "%s %s `%s'",
  761.             "This client doesn't know how to compose authentication",
  762.             "information for scheme", HTAAScheme_name(scheme));
  763.         HTAlert(msg);
  764.         auth_string = NULL;
  765.     }
  766.     } /* switch scheme */
  767.  
  768.     current_setup->retry = NO;
  769.  
  770.     /* Added by marca. */
  771.     if (!auth_string)
  772.     return NULL;
  773.     
  774.     if (!(result = (char*)malloc(sizeof(char) * (strlen(auth_string)+40))))
  775.     outofmem(__FILE__, "HTAA_composeAuth");
  776.     strcpy(result, "Authorization: ");
  777.     strcat(result, HTAAScheme_name(scheme));
  778.     strcat(result, " ");
  779.     strcat(result, auth_string);
  780.     return result;
  781. }
  782.  
  783.  
  784.  
  785.  
  786. /* BROWSER PUBLIC                HTAA_shouldRetryWithAuth()
  787. **
  788. **        DETERMINES IF WE SHOULD RETRY THE SERVER
  789. **        WITH AUTHORIZATION
  790. **        (OR IF ALREADY RETRIED, WITH A DIFFERENT
  791. **        USERNAME AND/OR PASSWORD (IF MISSPELLED))
  792. ** ON ENTRY:
  793. **    start_of_headers is the first block already read from socket,
  794. **            but status line skipped; i.e. points to the
  795. **            start of the header section.
  796. **    length        is the remaining length of the first block.
  797. **    soc        is the socket to read the rest of server reply.
  798. **
  799. **            This function should only be called when
  800. **            server has replied with a 401 (Unauthorized)
  801. **            status code.
  802. ** ON EXIT:
  803. **    returns        YES, if connection should be retried.
  804. **                 The node containing all the necessary
  805. **                 information is
  806. **                * either constructed if it does not exist
  807. **                * or password is reset to NULL to indicate
  808. **                  that username and password should be
  809. **                  reprompted when composing Authorization:
  810. **                  field (in function HTAA_composeAuth()).
  811. **            NO, otherwise.
  812. */
  813. PUBLIC BOOL HTAA_shouldRetryWithAuth ARGS3(char *, start_of_headers,
  814.                        int,       length,
  815.                        int,       soc)
  816. {
  817.     HTAAScheme scheme;
  818.     char *line;
  819.     int num_schemes = 0;
  820.     HTList *valid_schemes = HTList_new();
  821.     HTAssocList **scheme_specifics = NULL;
  822.     char *template = NULL;
  823.  
  824.  
  825.     /* Read server reply header lines */
  826.  
  827.     if (TRACE)
  828.     fprintf(stderr, "Server reply header lines:\n");
  829.  
  830.     HTAA_setupReader(start_of_headers, length, soc);
  831.     while (NULL != (line = HTAA_getUnfoldedLine())  &&  *line != (char)0) {
  832.  
  833.     if (TRACE) fprintf(stderr, "%s\n", line);
  834.  
  835.     if (strchr(line, ':')) {    /* Valid header line */
  836.  
  837.         char *p = line;
  838.         char *fieldname = HTNextField(&p);
  839.         char *arg1 = HTNextField(&p);
  840.         char *args = p;
  841.         
  842.         if (0==strcasecomp(fieldname, "WWW-Authenticate:")) {
  843.         if (HTAA_UNKNOWN != (scheme = HTAAScheme_enum(arg1))) {
  844.             HTList_addObject(valid_schemes, (void*)scheme);
  845.             if (!scheme_specifics) {
  846.             int i;
  847.             scheme_specifics = (HTAssocList**)
  848.                 malloc(HTAA_MAX_SCHEMES * sizeof(HTAssocList*));
  849.             if (!scheme_specifics)
  850.                 outofmem(__FILE__, "HTAA_shouldRetryWithAuth");
  851.             for (i=0; i < HTAA_MAX_SCHEMES; i++)
  852.                 scheme_specifics[i] = NULL;
  853.             }
  854.             scheme_specifics[scheme] = HTAA_parseArgList(args);
  855.             num_schemes++;
  856.         }
  857.         else if (TRACE) {
  858.             fprintf(stderr, "Unknown scheme `%s' %s\n",
  859.                 (arg1 ? arg1 : "(null)"),
  860.                 "in WWW-Authenticate: field");
  861.         }
  862.         }
  863.  
  864.         else if (0==strcasecomp(fieldname, "WWW-Protection-Template:")) {
  865.         if (TRACE)
  866.             fprintf(stderr, "Protection template set to `%s'\n", arg1);
  867.         StrAllocCopy(template, arg1);
  868.         }
  869.  
  870.     } /* if a valid header line */
  871.     else if (TRACE) {
  872.         fprintf(stderr, "Invalid header line `%s' ignored\n", line);
  873.     } /* else invalid header line */
  874.     } /* while header lines remain */
  875.  
  876.  
  877.     /* So should we retry with authorization */
  878.  
  879.     if (num_schemes == 0) {        /* No authentication valid */
  880.     current_setup = NULL;
  881.     return NO;
  882.     }
  883.  
  884.     if (current_setup && current_setup->server) {
  885.     /* So we have already tried with authorization.    */
  886.     /* Either we don't have access or username or    */
  887.     /* password was misspelled.            */
  888.         
  889.     /* Update scheme-specific parameters    */
  890.     /* (in case they have expired by chance).    */
  891.     HTAASetup_updateSpecifics(current_setup, scheme_specifics);
  892.  
  893.     if (NO == HTConfirm("Authorization failed.  Retry?")) {
  894.         current_setup = NULL;
  895.         return NO;
  896.     } /* HTConfirm(...) == NO */
  897.     else { /* re-ask username+password (if misspelled) */
  898.         current_setup->retry = YES;
  899.         return YES;
  900.     } /* HTConfirm(...) == YES */
  901.     } /* if current_setup != NULL */
  902.  
  903.     else { /* current_setup == NULL, i.e. we have a     */
  904.        /* first connection to a protected server or  */
  905.        /* the server serves a wider set of documents */
  906.        /* than we expected so far.                   */
  907.  
  908.     HTAAServer *server = HTAAServer_lookup(current_hostname,
  909.                            current_portnumber);
  910.     if (!server) {
  911.         server = HTAAServer_new(current_hostname,
  912.                     current_portnumber);
  913.     }
  914.     if (!template)
  915.         template = HTAA_makeProtectionTemplate(current_docname);
  916.     current_setup = HTAASetup_new(server, 
  917.                       template,
  918.                       valid_schemes,
  919.                       scheme_specifics);
  920.  
  921.         HTAlert("Access without authorization denied -- retrying");
  922.     return YES;
  923.     } /* else current_setup == NULL */
  924.  
  925.     /* Never reached */
  926. }
  927.  
  928.